#ifndef AFCORE_COMMON_LOG_FORMATER_PATTERN_
#define AFCORE_COMMON_LOG_FORMATER_PATTERN_

#include <ctime>

#include <memory>
#include <chrono>
#include <string>
#include <vector>
#include <unordered_map>

#include "nocopyable.h"
#include "duration.h"
#include "logcommon.h"
#include "log_msg.h"
#include "formater.h"

namespace afcore {

/// @brief  日志
namespace log {

/// @brief  填充信息
struct SPadInfo {
  /// @brief  填充规则
  enum EPadSide {
    kPadSideLeft,     ///< 左对齐
    kPadSideRight,    ///< 右对齐
    kPadSideCenter,   ///< 中央对齐
  };

  /// @brief  构造函数 默认
  SPadInfo() = default;
  /// @brief  构造函数
  SPadInfo(size_t width_in, EPadSide side_in, bool truncate_in)
    : width(width_in)
    , side(side_in)
    , truncate(truncate_in)
    , enable(true) {
  }

  /// @brief  是否可用
  /// @return 可用标志
  [[nodiscard]] bool Enabled() const { return enable; }

  size_t width {0};             ///< 填充宽度
  EPadSide side {kPadSideLeft}; ///< 填充规则
  bool truncate {false};        ///< 截断标志
  bool enable {false};          ///< 可用标志
};

/// @brief  格式化标志接口
class AFCORE_COMMON_API CFormaterFlag {
public:
  /// @brief  构造函数 显示
  explicit CFormaterFlag(SPadInfo padinfo)
    : padinfo_(padinfo) {
  }
  /// @brief  构造函数 默认
  CFormaterFlag() = default;
  /// @brief  析构函数 默认
  virtual ~CFormaterFlag() = default;
  /// @brief  格式化 纯虚
  /// @param  msg     日志信息
  /// @param  tm_time 日志时间
  /// @param  [out]   dest    fmt缓冲区
  virtual void Format(const SLogMessage& msg, const std::tm& tm_time, RMemoryBuf& dest) = 0;
protected:
  SPadInfo padinfo_;  ///< 填充信息
};

/// @brief  用户自定义格式化标志接口
class AFCORE_COMMON_API CFormaterFlagCustom
  : public CFormaterFlag {
public:
  /// @brief  复制用户自定义格式化标志 纯虚
  [[nodiscard]] virtual std::unique_ptr<CFormaterFlagCustom> Clone() const = 0;

  /// @brief  设置填充规则
  /// @param  padinfo     填充规则
  void SetPadInfo(SPadInfo padinfo) {
    CFormaterFlag::padinfo_ = padinfo;
  }
};

/// @brief  格式器模式
/// |内置解析标识 |模式含义                                       |
/// |------------|---------------------------------------------|
/// | '+'        | 默认                                         |
/// | 'n'        | 日志名称                                      |
/// | 'L'        | 日志级别缩写                                  |
/// | 'l'        | 日志级别                                     |
/// | 'A'        | 星期缩写                                     |
/// | 'a'        | 星期                                         |
/// | 'B'        | 月缩写                                       |
/// | 'b'        | 月                                          |
/// | 'C'        | 日期简写                                     |
/// | 'c'        | 日期                                        |
/// | 'Y'        | 年缩写                                      |
/// | 'y'        | 年                                          |
/// | 'm'        | 月 1-12                                     |
/// | 'd'        | 日 1-31                                     |
/// | 'h'        | 小时 0-23                                   |
/// | 'H'        | 小时 1-12                                   |
/// | 'M'        | 分钟 0-59                                   |
/// | 'S'        | 秒 0-59                                     |
/// | 'E'        | 毫秒                                        |
/// | 'F'        | 微妙                                        |
/// | 'G'        | 纳秒                                        |
/// | 't'        | 时间戳                                      |
/// | 'p'        | AM/PM                                      |
/// | 'r'        | 十二小时制AM/PM格式类                        |
/// | 'j'        | 二十四小时制格式化 小时:分钟                  |
/// | 'J'        | 二十四小时制格式类 ISO 8601 time  23:30:00   |
/// | 'T'        | 线程                                       |
/// | 'P'        | 进程                                       |
/// | 'v'        | 日志信息                                    |
/// | '%%'        | 字符                                        |
/// | '^'        | 颜色开始                                    |
/// | '$'        | 颜色结束                                    |
/// | '@'        | 源文件定位                                  |
/// | 'P'        | 进程                                       |
/// | 'v'        | 日志信息                                    |
/// | 'I'        | 源文件文件名不带路径                         |
/// | 'i'        | 源文件文件名带路径                           |
/// | '#'        | 源文件行号                                  |
/// | '!'        | 源文件函数名                                |
/// | 'g'        | 距离上次日志时间 纳秒                        |
/// | 'f'        | 距离上次日志时间 微秒                        |
/// | 'e'        | 距离上次日志时间 毫秒                        |
/// | 's'        | 距离上次日志时间                             |
class AFCORE_COMMON_API CFormaterPattern final
  : public CNocopyable
  , public CFormatter {
public:
  using RCustomFlags = std::unordered_map<char, std::unique_ptr<CFormaterFlagCustom>>;

  /// @brief  构造函数
  /// @param  pattern             格式化模式
  /// @param  pattern_time_type   格式使用的时间类型
  /// @param  eol                 结尾符
  /// @param  custom_user_flags   用户自定义匹配规则
  explicit CFormaterPattern(std::string pattern, EPatternTimeType pattern_time_type = EPatternTimeType::kPatternTimeTypeLocal,
    std::string eol = g_default_eol, RCustomFlags custom_user_flags = {});
  /// @brief  构造函数
  /// @param  pattern_time_type   格式使用的时间类型
  /// @param  eol                 结尾符
  explicit CFormaterPattern(EPatternTimeType pattern_time_type = EPatternTimeType::kPatternTimeTypeLocal,
    std::string eol = g_default_eol);

  /// @brief  日志格式化 重写
  /// @param  msg     日志
  /// @param  [out]   dest    fmt缓冲区
  void Format(const SLogMessage& msg, RMemoryBuf& dest) override ;
  /// @brief  复制格式器 重写
  RFormatterUptr Clone() const override;

  /// @brief  添加用户自定义格式解析
  /// @tparam T       用户自定义格式化类
  /// @tparam ...Args 额外参数
  /// @param  flag    格式字符缩写
  /// @param  ...args 额外参数
  /// @return 用户自定义格式匹配
  template<typename T, typename... Args>
  CFormaterPattern& AddFlag(char flag, const Args&... args) {
    custom_handlers_[flag] = std::make_unique<T>(args...);
    return *this;
  }

  /// @brief  设置模式匹配
  /// @param  pattern     模式匹配
  void SetPattern(std::string pattern);

private:
  /// @brief  获取时间
  /// @param  msg     日志信息
  /// @return 时间
  std::tm GetTime(const SLogMessage& msg);

  /// @brief  处理格式化标志
  /// @tparam Padder      填充标志
  /// @param  flag        标志
  /// @param  pad_info    填充规则
  template<typename Padder>
  void HandleFlag(char flag, SPadInfo pad_info);

  /// @brief  填充空格处理
  /// @param  [out]   iter    填充的迭代器
  /// @param  end         末尾界限
  static SPadInfo HandlePadSpec(std::string::const_iterator& iter, std::string::const_iterator end);

  /// @brief  解析格式化模式
  /// @param  pattern     解析格式
  void AnalyzePattern(const std::string& pattern);

private:
  std::string pattern_;                                     ///< 模式
  std::string eol_;                                         ///< 结尾符
  EPatternTimeType pattern_time_type_;                      ///< 模式时间格式(默认本地时间)
  std::tm cached_tm_;                                       ///< 缓存日期
  RSeconds last_log_secs_ {0};                          ///< 上次日志记录时间戳 单位秒
  std::vector<RFormaterFlagUptr> formatters_;               ///< 格式化列表
  RCustomFlags custom_handlers_;                            ///< 用户自定义格式化列表
};

} // !namespace log

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_FORMATER_PATTERN_